package com.bj58.mis.apm.server.statistics.dto.chart;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 图表数据对象
 */
@ApiModel(description = "图表数据对象")
public class ChartData {
    @ApiModelProperty(value = "类目数据")
    private List<String> category;
    @ApiModelProperty(value = "值对象")
    private List<ValueBean> valueBeans;

    @ApiModelProperty(value = "原始数据")
    private List<?> originalDatas;

    public List<String> getCategory() {
        return category;
    }

    public void setCategory(List<String> category) {
        this.category = category;
    }

    public List<ValueBean> getValueBeans() {
        return valueBeans;
    }

    public void setValueBeans(List<ValueBean> valueBeans) {
        this.valueBeans = valueBeans;
    }

    public List<?> getOriginalDatas() {
        return originalDatas;
    }

    public void setOriginalDatas(List<?> originalDatas) {
        this.originalDatas = originalDatas;
    }

    /**
     * 构建图表数据
     * @param datas
     * @param categoryFiled
     * @param valueFileds
     * @return
     */
    public static ChartData buildChartData(List<?> datas, String categoryFiled, String[] valueFileds){
        ChartData chartData = new ChartData();
        chartData.setOriginalDatas(datas);
        chartData.setCategory(datas.stream().map(data -> (String)getValue(data, categoryFiled)).collect(Collectors.toList()));
        chartData.setValueBeans(Arrays.stream(valueFileds).map(valueField -> {
            ValueBean bean = new ValueBean();
            bean.setName(valueField);
            List<Double> beanDataList = datas.stream().map(data -> ((Number)getValue(data, valueField)).doubleValue()).collect(Collectors.toList());
            bean.setData(beanDataList);
            return bean;
        }).collect(Collectors.toList()));
        return chartData;
    }

    /**
     * 构建图表数据
     * @param datas
     * @param categoryFiled
     * @param valueFileds
     * @param valueBeanNames
     * @param valueBeanSubNames
     * @return
     */
    public static ChartData buildChartData(List<?> datas, String categoryFiled, String[] valueFileds, String[] valueBeanNames, String[] valueBeanSubNames, String[] valueBeanUnits){
        ChartData chartData = buildChartData(datas, categoryFiled, valueFileds);
        return chartData.addNames(valueBeanNames, valueBeanSubNames, valueBeanUnits);
    }

    /**
     * 添加值名称和子名称，即图例名称
     * @param valueBeanNames
     * @param valueBeanSubNames
     * @return
     */
    public ChartData addNames(String[] valueBeanNames, String[] valueBeanSubNames, String[] valueBeanUnits){
        List<ValueBean> list = this.valueBeans;
        for(int i = 0; i < list.size() ; i++){
            ValueBean vb = list.get(i);
            if(valueBeanNames != null && valueBeanNames.length > i){
                vb.setName(valueBeanNames[i]);
            }
            if(valueBeanSubNames != null && valueBeanSubNames.length > i){
                vb.setSubName(valueBeanSubNames[i]);
            }
            if(valueBeanUnits != null){
                if(valueBeanUnits.length > i){
                    vb.setUnit(valueBeanUnits[i]);
                }else if(valueBeanUnits.length > 0){
                    vb.setUnit(valueBeanUnits[0]);
                }
            }
        }
        return this;
    }
    /**
     * 根据ValueBean数据，计算内部数据
     * @return
     */
    public ChartData calc(){
        this.valueBeans.forEach( vb -> {
            vb.setCount(vb.getData().size());
            vb.setSum(vb.getData().stream().mapToDouble(Double::doubleValue).sum());
            if(vb.getCount() > 0) {
                vb.setAvg(new BigDecimal(vb.getSum()).divide(new BigDecimal(vb.getCount()), 4, BigDecimal.ROUND_HALF_UP).doubleValue());
            }
        });
        return this;
    }

    /**
     * 读取对象值
     * @param obj
     * @param key
     * @return
     */
    private static Object getValue(Object obj, String key){
        if(obj instanceof Map){
            return ((Map)obj).get(key);
        }else{
            try {
                Class clazz = obj.getClass();
                Field f = clazz.getDeclaredField(key);
                f.setAccessible(true);
                return f.get(obj);
            }catch (Exception e){
                throw new RuntimeException("转换ChartData异常，对象读取失败！");
            }
        }
    }
}
